﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotNetStar.TheKing.Services
{
    using SDDP;
    using Domain;
    using DotNetStar.TheKing.Infrastructure;
    using DotNetStar.TheKing.Models;
    using Microsoft.Extensions.Caching.Memory;
    using Microsoft.EntityFrameworkCore;

    partial class ContentService
    {

        #region Comments
        /// <summary>
        /// 以异步方式创建一条评论。
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">model</exception>
        public async Task<ExecutedResult<ContentComment>> CreateCommentAsync(string body, long contentId, long userId)
        {


            var content = await _contentStorage.GetByIdAsync(contentId);
            if (content == null)
            {
                return ExecutedResult<ContentComment>.Failed("帖子不存在或已被删除");
            }

            var user = await _userService.GetByIdAsync(userId);
            if (user == null)
            {
                return ExecutedResult<ContentComment>.Failed("当前用户不存在");
            }

            if (content.OnlyInviteUser && !_contentInviteUserStorage.Query(m => m.ContentId == contentId).Any(m => m.UserId == user.Id))
            {
                return ExecutedResult<ContentComment>.Failed("该帖子仅允许指定用户进行回复");
            }

            var comment = new ContentComment
            {
                ContentId = contentId,
                Body = body
            };

            comment.SetAuthor(user);

            _contentCommentStorage.Add(comment);
            await _contentCommentStorage.Context.CommitAsync();


            _eventBus.Publish(new UserPointEvent(user.Id, PointStrategyTypes.ReplyContent));

            var contentAuthor = await _userService.GetByIdAsync(content.AuthorId);
            if (comment.AuthorId != content.AuthorId && contentAuthor != null)//回复人和作者不是同一个用户时发信息
            {
                _eventBus.Publish(new ContentReplyNotificationEvent(contentAuthor, content,
                    new SmsNotification(contentAuthor.Mobile, "SMS_126362872", new
                    {
                        name = contentAuthor.UserName,
                        cid = content.Id
                    })));
            }

            return ExecutedResult<ContentComment>.Success(comment);
        }

        /// <summary>
        /// 获取指定内容的评论分页。
        /// </summary>
        /// <param name="contentId">The content identifier.</param>
        /// <param name="page">The page.</param>
        /// <param name="itemsPerPage">The items per page.</param>
        /// <returns></returns>
        public Task<IEnumerable<ContentComment>> GetCommentsAsync(long contentId)
        => Task.Run(() =>
        (from c in
             _contentCommentStorage.Query(m => m.ContentId == contentId)
         join u in _userStorage.Query() on c.AuthorId equals u.Id
         select new ContentComment
         {
             Id = c.Id,
             Author = u,
             AuthorId = c.AuthorId,
             Body = c.Body,
             ContentId = c.ContentId,
             PostedTime = c.PostedTime
         }
    )
        .ToList().AsEnumerable()
        );


        /// <summary>
        /// 获取指定评论
        /// </summary>
        /// <returns></returns>
        public Task<ContentComment> GetCommentAsync(Guid commentId)
        =>
        (from c in
             _contentCommentStorage.Query()
         join u in _userStorage.Query() on c.AuthorId equals u.Id
         where c.Id == commentId
         select new ContentComment
         {
             Id = c.Id,
             Author = u,
             AuthorId = c.AuthorId,
             Body = c.Body,
             ContentId = c.ContentId,
             PostedTime = c.PostedTime
         }
    )
        .SingleOrDefaultAsync();

        /// <summary>
        /// 删除自己的评论
        /// </summary>
        /// <param name="commentId">The comment identifier.</param>
        /// <param name="userId">The user identifier.</param>
        /// <returns></returns>
        public async Task<ExecutedResult> DeleteCommentAsync(Guid commentId, long userId)
        {
            var comment = await _contentCommentStorage.FindAsync(commentId);
            if (comment == null)
            {
                return ExecutedResult.Failed("当前回复不存在。");
            }

            if (comment.AuthorId != userId)
            {
                return ExecutedResult.Failed("你没有权限删除当前回复");
            }

            var content = await _contentStorage.FindAsync(comment.ContentId);
            if (content == null)
            {
                return ExecutedResult.Failed("当前内容不存在或已被删除。");
            }

            //if (content.IsLockComment)
            //{
            //    return ExecutedResult.Failed("当前内容已禁止回复，不允许对回复进行操作");
            //}

            _contentCommentStorage.Remove(comment);
            await _contentCommentStorage.Context.CommitAsync();


            _eventBus.Publish(new UserPointEvent(comment.AuthorId, PointStrategyTypes.DeleteReply));

            return ExecutedResult.Success();
        }
        #endregion


        #region Category
        /// <summary>
        /// 以异步方式获取指定频道的所有分类。
        /// </summary>
        /// <param name="channel"></param>
        /// <returns></returns>
        public Task<IEnumerable<Category>> GetCategoriesAsync()
            => base.MemoryCache.GetOrCreateAsync("Categories", (entry) =>
             Task.FromResult(_categoryStorage.Query(m => m.Enabled).ToList().AsEnumerable())
            );

        public async Task<IEnumerable<Category>> GetCategoriesByParentAsync(int pid = 0)
            => (await GetCategoriesAsync()).Where(m => m.ParentId == pid);
        

        public async Task<Category> SaveCategoryAsync(Category item)
        {
            if (item.Id == 0)
            {
                _categoryStorage.Add(item);
            }
            else
            {
                var entity = await _categoryStorage.FindAsync(item.Id);
                entity.Name = item.Name;
                entity.DisplayOrder = item.DisplayOrder;
                entity.Enabled = item.Enabled;
            }

            await _categoryStorage.Context.CommitAsync();
            return item;
        }

        public async Task DeleteCategoryAsync(int categoryId,long? userId)
        {
            var item = await _categoryStorage.Query(m => m.Id == categoryId).SingleOrDefaultAsync();
            if (item == null)
            {
                throw new NullReferenceException("找不到指定分类");
            }

            _categoryStorage.Remove(item);
            await _categoryStorage.Context.CommitAsync();
            if (!userId.HasValue)
            {
                base.MemoryCache.Remove("Categories");
            }
        }

        /// <summary>
        /// 获取指定id的分类
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        public Task<Category> GetCategoryAsync(int id = 0)
        =>
             (from c in _categoryStorage.Query()
              where c.Id == id
              select new Category
              {
                  Id = c.Id,
                  DisplayOrder = c.DisplayOrder,
                  Enabled = c.Enabled,
                  ParentId = c.ParentId,
                  Name = c.Name,
                  ParentCategory = _categoryStorage.Query().SingleOrDefault(m => m.Id == c.ParentId)
              }).SingleOrDefaultAsync();

        #endregion

        #region PayContent
        /// <summary>
        /// 向指定的内容付费。付费不成功会有异常。
        /// </summary>
        /// <param name="contentId">要付费的帖子id</param>
        /// <param name="userId">要付费的用户id.</param>
        /// <returns></returns>
        public async Task PayContentAsync(long contentId, long userId)
        {
            var content = await _contentStorage.FindAsync(contentId);
            if (content == null)
            {
                throw new NullReferenceException("指定的内容不存在");
            }

            if (!content.Cost.HasValue)
            {
                //没设置收费，则不走下面的内容
                return;
            }

            if (await IsContentPaid(contentId,userId))
            {
                return;
            }

            //付费者
            var user = await _userService.GetByIdAsync(userId);
            
            //作者
            var author = await _userService.GetByIdAsync(content.AuthorId);

            //此操作会抛出异常，记得捕获
            try
            {
                _eventBus.Publish(new TradingPointTrasitionEvent(user.Id, author.Id, content.Cost.Value, $"付费阅读【{content.Subject}】帖子"));

                _userContentPayStorage.Add(new UserContentPayHistory
                {
                    ContentId = contentId,
                    UserId = userId,
                    Cost = content.Cost.Value,
                });
                await _userContentPayStorage.Context.CommitAsync();
            }catch(Exception ex)
            {
                throw ex;
            }
        }

        public Task<bool> IsContentPaid(long contentId, long userId)
            =>Task.Run(()=> _userContentPayStorage.Query(m => m.ContentId == contentId).Any());

        /// <summary>
        /// 获取指定帖子付费的所有用户
        /// </summary>
        /// <param name="contentId"></param>
        /// <returns></returns>
        public Task<IEnumerable<Tuple<User,UserContentPayHistory>>> GetPaidUsersAsync(long contentId)
            => Task.Run(() =>
             (from u in _userStorage.Query()
             join p in _userContentPayStorage.Query() on u.Id equals p.UserId
             where p.ContentId == contentId
             orderby p.CreatedTime ascending
             select new
             {
                 u,p
             }
            ).Select(m=>Tuple.Create(m.u,m.p)).ToList().AsEnumerable())
            ;
        #endregion
    }
}
